{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MNIST Image Classification with an RNN Model\n",
    "\n",
    "### Build the dataset and dataloader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "from torchvision import transforms\n",
    "\n",
    "# Define the transformations to apply to the data\n",
    "transform = transforms.Compose([\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize((0.5,), (0.5,))\n",
    "])\n",
    "\n",
    "# Load the MNIST dataset\n",
    "train_dataset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)\n",
    "test_dataset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)\n",
    "\n",
    "# Create the data loaders\n",
    "batch_size = 64\n",
    "train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n",
    "test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualize samples from the dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA8gAAAPdCAYAAABWSUEqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAABtE0lEQVR4nO3deZzVZd0//tewpuLGoiImIKSYpaJGrrkmouSWS2ouuWSu3bmlueCatn29M+XW1MDUkixMyn3hdktTUyvNjRK3AnHLfQHP749+ekf6uc5wZoZZeD4fD/9wXvM+52LgGubFgXk31Wq1WgAAAGAB1629DwAAAAAdgYIMAAAAUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCnKrmjhxYpqamnLvvfe2yuM1NTXl4IMPbpXH+vfHPPHEExuaPfHEE9PU1FT532WXXdaqZ4WOoKvf6/c9+OCD2XHHHTNgwID07t07Q4YMyYEHHtg6B4QOpqvf6z/84Q856KCD8ulPfzqLLrpoll566Wy22Wa5+eabW/WM0JF09Xvt6/D5p0d7H4DOY999980WW2zxobfvt99++etf//qRGdDxTZ06NVtttVU22GCDnHvuuenfv3+eeuqp3H///e19NKABP//5z3P33Xdn7733zmqrrZbXX3895557bjbddNNcdNFF2WOPPdr7iMA88nX4/KMg02zLLbdclltuubneNn369Dz00EPZbbfdssQSS7TPwYCGvfHGG9ltt92yySab5De/+U2ampo+yHbfffd2PBnQqKOOOirf//7353rblltumTXWWCMnn3yyggydkK/D5x9/xXo+e+utt3L44Ydn9dVXz+KLL56+fftmnXXWyZVXXlk5c95552XFFVdM796988lPfvIj/wrFjBkzsv/++2e55ZZLr169MnTo0Jx00kmZPXt2W/5w8pOf/CS1Wi377rtvmz4PdGSd+V5ffvnl+cc//pEjjzxyrnIMC7rOfK+XWmqpD72te/fuWXPNNfP000+32vNAZ9OZ7/VH8XV42/AK8nz29ttv58UXX8wRRxyRQYMG5Z133smNN96Y7bffPhMmTPjQn+pOmTIlU6dOzcknn5xFFlkk48ePzy677JIePXpkhx12SPKvSzlq1Kh069YtJ5xwQoYNG5Y777wzp556aqZPn54JEyYUzzRkyJAk//pTqHnx3nvvZeLEiRk+fHg23HDDeZqFrqQz3+tbb701STJnzpysv/76ufvuu7PIIotkiy22yA9+8IMsu+yyjX1QoJPrzPf6o8yePTu33XZbVllllXmeha6iK91rX4e3oRqtZsKECbUktXvuuafZM7Nnz669++67tX322ac2cuTIubIktYUWWqg2Y8aMud5/xIgRteHDh3/wtv3337/Wp0+f2pNPPjnX/Pe///1aktpDDz0012OOGzdurvcbNmxYbdiwYc0+8/uuueaaWpLa6aefPs+z0Fl09Xs9evToWpLaEkssUTvqqKNqN998c+3cc8+t9evXrzZ8+PDa66+/3uwfN3QWXf1ef5Rjjz22lqT261//uqF56OgWtHvt6/C2469Yt4PLL7886623Xvr06ZMePXqkZ8+eufDCC/Pwww9/6H033XTTLL300h/8f/fu3bPzzjtn2rRpeeaZZ5Ikv/3tb7Pxxhtn2WWXzezZsz/4b8yYMUmSW265pXieadOmZdq0afP847jwwgvTo0eP7LXXXvM8C11NZ73X7733XpJk5513zne+851svPHG2X///XPhhRdm2rRp+dnPftbsjwF0NZ31Xv+nCy64IKeddloOP/zwbLPNNvM8D11JV7nXvg5vOwryfDZ58uTstNNOGTRoUC655JLceeedueeee7L33nvnrbfe+tD7L7PMMpVve+GFF5IkM2fOzG9+85v07Nlzrv/e/2tUzz//fKv/OJ5//vlMmTIlW2211UeeERYknfle9+vXL0kyevToud4+evToNDU15b777muV54HOpjPf6383YcKE7L///vnqV7+a733ve63++NCZdJV77evwtuXfIM9nl1xySYYOHZpJkybN9Q1x3n777Y98/xkzZlS+7f0vbPv3759VV101p5122kc+Rlv8G8KLL74477zzjm8KAOnc93rVVVct7k7s1s2fo7Jg6sz3+n0TJkzIvvvumz333DPnnnuub8THAq8r3OvE1+FtTUGez5qamtKrV6+5LuWMGTMqv3veTTfdlJkzZ37w1zvmzJmTSZMmZdiwYR98q/exY8fm6quvzrBhw7Lkkku2/Q8i//prHcsuu+wHf30EFmSd+V5vt912OfbYY3PNNddku+22++Dt11xzTWq1WtZee+02e27oyDrzvU6SiRMnZt99982Xv/zlXHDBBcoxpPPf6/f5OrxtKcht4Oabb/7I70S35ZZbZuzYsZk8eXIOPPDA7LDDDnn66adzyimnZODAgXn88cc/NNO/f/9ssskmOf744z/47nmPPPLIXK/4nHzyybnhhhuy7rrr5tBDD81KK62Ut956K9OnT8/VV1+dc88990N70/7d8OHDk6TZ//7h97//fR566KF861vfSvfu3Zs1A51dV73XI0aMyEEHHZTx48dn0UUXzZgxY/LYY4/luOOOy8iRI7PTTjs18yMEnU9XvdeXX3559tlnn6y++urZf//9c/fdd8+Vjxw5Mr179y4+BnRWXfVev8/X4fNBe3+XsK7k/e+eV/XfE088UavVarUzzjijNmTIkFrv3r1rK6+8cu3888+vjRs3rvafPx1JagcddFBt/PjxtWHDhtV69uxZGzFiRO3SSy/90HPPmjWrduihh9aGDh1a69mzZ61v3761Nddcs3bsscfWXnvttbke8z+/e97gwYNrgwcPbvaPc7/99qs1NTXV/vrXvzZ7BjqrBeFez549u3bGGWfUhg8fXuvZs2dt4MCBtQMOOKD20ksvzcuHCjqNrn6v99xzz2b9+KAr6er3+n2+Dm97TbVardYGvRsAAAA6Fd99BQAAAKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkSXo09x2bmpra8hywwOhIm9Xca2gd7jV0Pe41dD3NuddeQQYAAIAoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgSdKjvQ8AQNez0UYbVWZTp05t+HFPOumkYn7iiSc2/NgseBZZZJFiPmrUqMrs85//fHG2d+/eldlhhx1WPlgLTJo0qZiX7sizzz5bnH399dcrs/fee684C9BZeAUZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACBJ0lSr1WrNesemprY+CywQmnnl5gv3mpLSvtQNN9ywOFvag9yW2uvXtHvdOT3++OPFfNiwYQ0/dunnoSP9epkXF198cWV29NFHF2f/8Y9/tPZx2lxH+nlyr6F1NOdeewUZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRJerT3Aeg4Sitd6vnf//3fhrJ6zztu3LjGDtQMViawICitW6p3v9prVVPpc8ZJJ500/w5Cl1dvNdFxxx1Xmf3xj38szt5yyy2VWVuuD/rSl75UzFdZZZXKbNCgQcXZ3XffvTJ7+eWXi7Nf//rXizlAR+EVZAAAAIiCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJElTrZnL+OyM7fimTp1azNtrp2lHVdqn2pKd0PW05f7LeeVed371fq225S7xkpbsMq63O70jcq/pLAYOHFiZTZ48uTj72c9+tjKbNm1acXbVVVetzN56663ibHtxr/lPAwYMqMyWX375Nnvebbfdtph/8pOfbHj2vvvuq8w+85nPFGc7o+bca68gAwAAQBRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAk1jy1i9K6pXorWdpyVVNptUpXXBHVXr+mrY1omXrrzG655ZbKrC3Xd7VER/2cULLxxhsX8864qqkl3Gu6gp122qmYX3bZZQ0/9n777VeZXXjhhQ0/bltyr7um7bbbrjLbfvvti7Prr79+ZVZvzVO9X0+ln+O2nH366acrs3prnp5//vli3hFZ8wQAAADNpCADAABAFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCRJj/Y+QFdUb9dqvb2mJaXdoqX9r0nb7oDtSLsC31dvTyudU71f551x/27pc0J77T5P3CGg9dxxxx3tfQQ6mAEDBlRma665ZnF22223behx683W2zdd+nq3pbuqS/uIZ82aVZyt9/EqueKKKyqzzrjnuDV4BRkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJEmaas3cz9PSb13e1bTXWqPS2pX2XG/j49F8HWkllnvdekrrmKZOnTr/DvIfTjrppMqsLVe/LWjcazqLgQMHVmaldS9JMmrUqIafd9FFF63MXn/99YYfty251y1Tb93S1VdfXZmtscYaxdmWrFsqzZ5//vnF2bZcifTUU09VZvvvv39x9uSTT67M6v06Ln39cvvttxdnO6Pm3GuvIAMAAEAUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJEl6tPcBmFtH3XPXXntcS3uOk46765iup97O4HHjxrXJ89b7NV7vjgALlmWWWaaY//rXv67MPvOZz7TyaaBa//79K7Nu3cqv4T333HOV2YYbblicfeSRR8oHayeDBw+uzA499NDibKk/3HbbbcXZrrjruKW8ggwAAABRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkljz1LCTTjqpMqv37eVLs+2ptMppo402arPnLa2xscaJ+am0yqmt1jgl5V/n1jgB8+Lss88u5m21yunCCy8s5m+88UabPC8d16xZs4r5mDFjKrOFF164OPv8889XZk899VT5YB3UBhtsUJn169evOFur1Sqzb3/72w2faUHlFWQAAACIggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCRJU620OOvf37Gpqa3PQhsr7TlO2m7Xcb29z6Xds11RM6/cfOFez62tfm7q7fPuqLuO22ovdFf8nOBe01Ecf/zxxbze/Sv505/+VJltsskmxdkXX3yx4edtL+41rWnAgAHF/JZbbqnMVlpppeLsD3/4w8rssMMOKx9sAdOce+0VZAAAAIiCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQJOnR3geg9dRbjdJWa5yS8hqbzriyha6p3qqzlijdgfZc41T6Mbfl54SSlqyI8vkEkiFDhlRme+21V3G2tC5o9uzZxdntt9++MuuMa5xgfjrmmGOKeWmVU73VRN/+9rcbOhMfzSvIAAAAEAUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJ7EHudEo7QFuyW7Se0o7XpH33vMK/K92Rluz9ba87UO/M9e59e+06hnmx5JJLFvM999yzMqu3H3TRRRetzJZaaqni7FlnnVWZvf7668XZf/zjH8W8pLTnOEluuOGGymzo0KHF2bvvvrsyq/f55G9/+1sxhwXZN77xjWL+9a9/vZiXdpTvsccexdnnn3++mDNvvIIMAAAAUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJDEHuQOp7TDNWm/Xcf2HNNZbLjhhm3yuCeddFKb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AAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKcquaOHFimpqacu+997bK4zU1NeXggw9ulcf698c88cQTG56fNm1adt999yy//PJZaKGFMmzYsBx22GF54YUXWu+Q0IF09Xv99NNPZ7vttssKK6yQRRZZJIsvvnhGjhyZs88+O7Nnz27Vc0JH0dXvdZI89thj+eIXv5gll1wyCy+8cD772c9mypQprXdA6GC6+r2ePn16mpqaPvK/yy67rFXPuaDr0d4HoPOYNWtW1l577Sy22GI55ZRTsvzyy+f+++/PuHHjMnXq1PzhD39It27+zAU6k9dffz2LLbZYjj/++Cy//PJ55513cvXVV+eQQw7JAw88kAsuuKC9jwjMo+nTp2edddbJwIEDc+6556ZPnz75n//5n2y77ba5/PLL88UvfrG9jwg06JBDDsmuu+4619s+8YlPtNNpuiYFmWa78sor88ILL2TSpEnZdNNNkyQbb7xx3n777XzrW9/KH//4x4wcObKdTwnMixEjRuSiiy6a621jxozJc889l4suuijnnHNOevfu3U6nAxpxxhln5I033sh1112XQYMGJUm22GKLfPrTn843vvGNbLfddv5AGzqp5ZdfPmuvvXZ7H6NL89lxPnvrrbdy+OGHZ/XVV8/iiy+evn37Zp111smVV15ZOXPeeedlxRVXTO/evfPJT37yI/8axYwZM7L//vtnueWWS69evTJ06NCcdNJJrfpXJHv27JkkWXzxxed6+xJLLJEk+djHPtZqzwWdSWe+11UGDBiQbt26pXv37m3+XNARdeZ7fccdd2S11Vb7oBwnSffu3TNmzJg8/fTTufvuu1vtuaAz6cz3mvnHK8jz2dtvv50XX3wxRxxxRAYNGpR33nknN954Y7bffvtMmDAhe+yxx1zvP2XKlEydOjUnn3xyFllkkYwfPz677LJLevTokR122CHJvy7lqFGj0q1bt5xwwgkZNmxY7rzzzpx66qmZPn16JkyYUDzTkCFDkvzrr2SVbLvttll++eVz+OGHZ/z48Rk8eHDuu+++nHHGGfnCF76QlVdeueGPC3Rmnflev69Wq2XOnDl59dVXc/3112fixIk5/PDD06OH3yZYMHXme/3OO++kb9++H3r7+38b5E9/+pNXoFggdeZ7/b4zzjgj3/rWt9KjR4+sscYaOeqoo7L11lvP88eCghqtZsKECbUktXvuuafZM7Nnz669++67tX322ac2cuTIubIktYUWWqg2Y8aMud5/xIgRteHDh3/wtv3337/Wp0+f2pNPPjnX/Pe///1aktpDDz0012OOGzdurvcbNmxYbdiwYc0679///vfaOuusU0vywX877rhj7a233mruDxk6lQXhXtdqtdrpp5/+wZ1uamqqHXvssc2ehc6mq9/rbbfdtrbEEkvUXn311bnevsEGG9SS1L797W/XfQzobLr6vf773/9e22+//Wq/+MUvarfddlvt0ksvra299tq1JLXzzz+/2T9m6vNXrNvB5ZdfnvXWWy99+vRJjx490rNnz1x44YV5+OGHP/S+m266aZZeeukP/r979+7ZeeedM23atDzzzDNJkt/+9rfZeOONs+yyy2b27Nkf/DdmzJgkyS233FI8z7Rp0zJt2rS6537ppZeyzTbb5JVXXsmll16aW2+9NePHj8/tt9+erbfe2l8jYYHWWe/1+/baa6/cc889ue6663LUUUfle9/7Xg455JBmz0NX1Fnv9cEHH5x//vOf2WOPPfK3v/0tM2fOzPHHH5/f/e53SeLfH7NA66z3euDAgfnxj3+cHXfcMeuvv3523XXX3HrrrRk5cmSOPvpoX4e3Ip8h57PJkydnp512yqBBg3LJJZfkzjvvzD333JO99947b7311ofef5lllql82/urlWbOnJnf/OY36dmz51z/rbLKKkmS559/vlXO/p3vfCcPPPBAbrjhhuy6667ZYIMNcsABB+TSSy/N9ddfn0svvbRVngc6m858r//9+ddaa61svvnmOeOMM3LyySfn7LPPzv3339+qzwOdRWe+15tuumkmTJiQW2+9NcOGDcsyyyyTyZMn55RTTkmSuf5tMixIOvO9/ig9e/bMzjvvnBdeeCGPP/54mz3PgsY/LpvPLrnkkgwdOjSTJk1KU1PTB29/++23P/L9Z8yYUfm2fv36JUn69++fVVddNaeddtpHPsayyy7b0mMnSR544IEMGjQoAwcOnOvtn/nMZ5IkDz74YKs8D3Q2nfleVxk1alSSf+1S9d3pWRB19nu95557Zrfddsvjjz+enj17Zvjw4Tn99NPT1NSUDTbYoNWeBzqTzn6vP0qtVkvib4a0JgV5PmtqakqvXr3mupQzZsyo/O55N910U2bOnPnBX++YM2dOJk2alGHDhmW55ZZLkowdOzZXX311hg0bliWXXLLNzr7sssvmpptuyrPPPjvXnz7feeedSfLBeWBB05nvdZWpU6cmSYYPHz7fnxs6gq5wr3v06PHBN9D85z//mR//+MfZZpttMnjw4DZ/buiIusK9/nfvvvtuJk2alP79+/v9uhUpyG3g5ptv/sjvRLfllltm7NixmTx5cg488MDssMMOefrpp3PKKadk4MCBH/lXI/r3759NNtkkxx9//AffPe+RRx6Z61vMn3zyybnhhhuy7rrr5tBDD81KK62Ut956K9OnT8/VV1+dc889t1he379Q9f79w0EHHZRLL700n//853P00Ufn4x//eB588MGceuqpWXrppbPbbrs18yMEnU9Xvdfjxo3LzJkz87nPfS6DBg3Kyy+/nGuvvTbnn39+dtxxx6y55prN/AhB59NV7/Vzzz2XH/zgB1lvvfWy6KKL5pFHHsl3v/vddOvWLeecc04zPzrQOXXVe33YYYfl3XffzXrrrZdlllkmTz/9dH70ox/lgQceyIQJE6xlbE3t/V3CupL3v3te1X9PPPFErVar1c4444zakCFDar17966tvPLKtfPPP782bty42n/+dCSpHXTQQbXx48fXhg0bVuvZs2dtxIgRtUsvvfRDzz1r1qzaoYceWhs6dGitZ8+etb59+9bWXHPN2rHHHlt77bXX5nrM//zueYMHD64NHjy4WT/G++67r7bddtvVlltuuVrv3r1rK6ywQm3fffetPfXUU/P0sYLOoqvf6ylTptQ222yz2tJLL13r0aNHrU+fPrVRo0bVzjrrrNq77747zx8v6Ay6+r1+4YUXaptvvnltwIABtZ49e9aWX3752iGHHFKbNWvWPH+soLPo6vf6wgsvrI0aNarWt2/fWo8ePWpLLrlkbfTo0bXrrrtunj9WlDXVav//X1wHAACABZh/zQ0AAABRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkCTp0dx3bGpqastzwAKjI60ed6+hdbjX0PW419D1NOdeewUZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkCTp0d4H6Iq6d+9ezA8//PDK7PTTTy/OXnLJJZXZnnvuWT4Y0LC11167mH/hC1+ozNZdd93ibO/evRt+3npmzpxZmf3kJz8pzl588cWV2eOPP16cnTNnTvlgAAAdkFeQAQAAIAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSJE21Wq3WrHdsamrrs3QZ/fr1K+aPPvpoZbbEEksUZ0t7kPfaa6/ibD1rrrlmZTZo0KDi7A033FCZvfnmmw2fqStq5pWbL9zrua2++uqV2c0331ycXXzxxRt+3tLPQ719ws8991wxL31O+djHPlacLTnppJOK+Q9/+MPK7J///GfDz9tRudfQ9bjX0PU05157BRkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJEl6tPcBuqIXXnihmF911VWV2W677VacnT59eiNHSpL07t27mJ9++umV2SabbFKcPe200yqzcePGlQ8GHcTAgQMrs4UXXrjhx33ppZeK+ZFHHlmZvfHGG8XZSZMmFfPSuqW99967OFv6Mde715/61Kcqs1133bU4O3v27GIOHcH6669fzA888MDKbJdddinOtuV6od/+9reV2be//e3i7F133dXaxwHocLyCDAAAAFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQJGmqNXPZXlNTU1ufpcv43Oc+V8wnT55cmT388MPF2c0337wye/PNN4uzG2+8cTG/4YYbinnJ5z//+cps6tSpDT9uV9SW+y3nlXvdfGPGjCnmiyyySGX2yCOPFGcffPDBhs7UUvvtt18xP/fcc9vkeQ8++OBi/j//8z9t8rxtyb3uuEr7vA855JDi7AknnFCZ9erVqzjbrVv1axD1fo7a69fTyy+/XMzXXHPNymz69Omte5gOwL3mPy211FKV2XPPPTcfT9IxlLrFP/7xj+LsEkssUZk988wzxdl6eUlz7rVXkAEAACAKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAkqRHex+gK7rqqquK+UILLVSZvfbaa8XZequcSuqtqWmJWbNmtdljQ0dwzTXXtPcRWl29tXJtpbQSC+bVaqutVsyPOOKIymzXXXctzr777ruV2S233FKc/dWvflWZ3XnnncXZJ598spgvv/zyldnIkSOLs3vssUdlNnTo0OLsiiuuWJl1xTVPLHh22WWXYn7SSSdVZj/84Q+Ls6+88kpDZ0qS9ddfv5iXVib17NmzOLvFFls0cqQkSe/evSuzOXPmFGdLq/CeffbZ4uzgwYPLB2shryADAABAFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACSxB7lN9OnTp5i/9957ldmtt97a2sf5QFNTU8P5DTfcUJx98MEHGzoT0LYWW2yxyuywww5rs+d95plnKrMLL7ywzZ6XrmmHHXaozOr9eurRo/pLnfPPP784e+KJJ1ZmM2bMKM62pZdeeqky++Mf/1icvfTSSyuzhRZaqDjbkj2u0FEsvPDCldm5555bnC19jX/WWWc1fKak/HV4rVZr0WO3ldK5pk2b1vDjXn/99Q3PtgavIAMAAEAUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJNY8tYnSGqckeeqppyqziRMntvJp/k+9bxFfyjvqt5eHrq7e2pWxY8cW81133bUy23rrrRs6U3P86Ec/qsxKK2pYMI0aNaqYl1YTzZ49uzi77777VmY///nPywfrgt59993KbNllly3OWvNEZ1Ba45Qkl112WWVWb1Vre3n99deL+R/+8IeGH/t3v/tdZVZvVdNtt93W8GxH5hVkAAAAiIIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAk9iC3iyWXXLIyW3vttYuzV1xxRcPPu8MOOxTz1157rTL78Y9/3PDzAmU9e/aszC666KLi7Be/+MXWPk6zfOc73ynmP/zhD+fTSegKtt1222Je2nVc2nOcLJi7jkuWWmqpyuzWW28tzp544omV2YQJExo9EsyzFVZYoTI79thji7NbbbVVax+nWe6///5ivummm1Zmc+bMKc6WvoZn3nkFGQAAAKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkSZpqtVqtWe/Y1NTWZ+ky6n0r9tKH/MEHHyzObrzxxpXZN7/5zeLskUceWcz/+Mc/VmZrrLFGcZbma+aVmy/c645h8uTJldk222zTZs/797//vZh/73vfq8z+53/+pzj77rvvNnSmzsq9bpnHHnusmD/77LOVWen3RT5srbXWqsx+//vfF2enTZtWma200koNn6mjcq/bT71fTzfeeGNltuyyy7b2cVpFva/xR48eXZnNmDGjtY+zwGrOvfYKMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAkqRHex+gKxo/fnwxP+CAAyqzT33qU8XZRx99tDJbYoklirP1nHvuuS2aBxqz7bbbVmYt3cM5c+bMymyLLbYozj700EMtem5ortdee62Y33333fPpJF3fjjvu2PDsAw880HoHgYJdd921mLdk1/Grr75amd10003F2RdffLEy+9KXvlScrfc1/l577VWZnXHGGcVZWpdXkAEAACAKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEmue2sTRRx9dzJ988snKrN63tV9ttdUaOlOSvPHGG8X88ccfr8x69+5dnH377bcbOhOQzJ49uzLr0aNln6YHDhxYmR133HHF2ZNOOqkyK32+SJI5c+aUDwb/Zvnlly/mP/zhD+fTSTqH7t27V2Zf/epXi7MHHnhgw8/7xBNPNDwL82LKlCnF/NOf/nRlVm9V089+9rPK7KWXXirO9uvXrzIrrWxMkoUXXriYjx49ujI777zzirP1zs288QoyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAECSpKlWq9Wa9Y5NTW19FpJsvvnmxfzqq69u+LHr/RyWfin85Cc/Kc5+/etfr8zefPPN8sEWMM28cvOFe90xrL322pXZscceW5zdcsstW/s4zXLMMccU8+9+97vz6SQdg3vdMs8//3wxP+iggyqzSZMmtfZx2t2hhx5azHfYYYfKbL311mvt43zgs5/9bGV27733ttnzthf3mv9U2oP86KOPFmf79u1bzEs/x/V+T/3mN79ZzPk/zbnXXkEGAACAKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiS9GjvAzC3wYMHNzz75JNPFvNf/vKXxfzwww+vzPbee++GzpQkhxxySDF/++23G35s6AruuuuuymznnXcuzu6///7F/MQTT6zM+vTpU5xtyfNOnDixMnvuuecafl66pno7Xs8+++zKbIUVVijO/uUvf2noTPXUe97PfOYzldkuu+xSnG3J/t0HH3ywmP/jH/+ozD7/+c83/LywINh0000rs969exdnW3KvO9JO7gWBV5ABAAAgCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBJrnjqcL37xiw3Pbr311sX8scceK+bvvfdeZXbkkUcWZ0troH7+858XZ6dOnVrM6XpGjBhRzP/rv/6rMjvmmGOKsy+99FIjR+qw3njjjWJ+5plnFvM777yzMjvhhBOKs6NHj67MhgwZUpzdc889K7Pvfe97xVkWPL/+9a+L+V577VWZnXrqqa17mPmg3sqWiy++uJj/4he/qMyuu+664uy4ceMqs80226w4C/Oi3tqjLbfcsjK74oorWvs4raK0om3hhRdu0WOX1p5Onz69RY/NvPEKMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEnuQu5RZs2YV83fffbeYl3aidutW/rOUww8/vDI77rjjirP2IC94DjjggGK+3377VWaf+cxnirOlnagdda9iW7rrrrsqs29/+9vF2dIe5HpWWmmlhmdZ8Hzta18r5g8++GBltvXWW7f2cZrllltuKea///3vK7PSvUySl19+uZjX26NcMmDAgIZnYV4ce+yxxfxb3/pWZXbfffcVZ4855pjK7A9/+EP5YAWlrz+SZOzYsQ0/dj1vvvlmZTZp0qQ2e14+zCvIAAAAEAUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJNU8dzhtvvFHMm5qaKrOFF164Rc9dWgP1P//zP8XZL3/5y5XZRhtt1OiR6KL+9re/NTy7+uqrF/Of/OQnlVm9dTBf//rXK7NXXnmlONsZDR8+vL2PAEnqryE888wzG8r4sJbc+8GDB1dm9957b8OPS9f0hS98oZiXvqZdc801i7PXX399Q2fqyEqrq1566aX5eBK8ggwAAABRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkCRpqtVqtWa9Y2FXGa1n8803L+ZXX311Zfbwww8XZzfddNNi/txzzxXzkvvvv78y+/SnP12c7dFjwVrH3cwrN1+0171ecskli3lpn+aQIUNa+TT/57HHHqvM7rrrruLsNddcU5n95S9/Kc5+4hOfqMyuuOKK4uxaa61VzA877LDKbMsttyzOLrroosW8ZMKECZXZvvvu2/DjdlTuNZ3F448/XpmtsMIKxdnPfvazlVlX3IPsXrfMUkstVcxLv2+uvvrqrXyatjd9+vRi/u1vf7uYX3jhha14Gqo05157BRkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJLHmqcPp169fMS+tmhk6dGhxtt63j7/11lsrs9133704u/baa1dmffr0Kc5a89R+Ouq9HjFiRGV21VVXFWfbcg1Uo1566aViXlp79de//rU4W2+NRktWNbWEdTDtp6PeazoGa56az71uW6Xfv0orCpPkoIMOqsy6dWv89b+///3vxXz8+PGV2SWXXFKcnTVrVkNnonVZ8wQAAADNpCADAABAFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCT2IHc63/jGNyqz733ve8XZej+HbbXv76KLLirm++yzT5s8b0dlr2LLLLHEEsV8+PDhldmXv/zl4uwuu+xSmfXv37842xKln4f2/PXy5JNPVmbbbrttcfYvf/lLZTZ79uxGj9Rhudd0FvYgN597DV2PPcgAAADQTAoyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEmseep0Flpoocrsm9/8ZnH2+OOPL+alXwqldS9Jcsopp1Rmv/zlL4uzr732WjHvaqyN6LhK92vkyJHF2TFjxlRmRx55ZHG2V69elVlLf71cccUVldmNN95YnJ04cWJl9tZbbzV6pC7JvaazaMmap+9+97uV2UMPPVScveSSS8oH64Dca+h6rHkCAACAZlKQAQAAIAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASe5BhvrNXEboe95rOorT/fOONNy7Oln6d19v3fuaZZ5YP1gG519D12IMMAAAAzaQgAwAAQBRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJAk6dHeBwAAoP099NBDxfzSSy+tzDrjGieAj+IVZAAAAIiCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJElTrVarNesdm5ra+iywQGjmlZsv3GtoHe41dD3uNXQ9zbnXXkEGAACAKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEmSplqtVmvvQwAAAEB78woyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBblVTZw4MU1NTbn33ntb5fGamppy8MEHt8pj/ftjnnjiia3yWDfeeGOamprS1NSU559/vlUeEzqaBeVeP/jgg9lxxx0zYMCA9O7dO0OGDMmBBx7YOgeEDqar3+unn3462223XVZYYYUsssgiWXzxxTNy5MicffbZmT17dqueEzqKrn6v/5Ovw9tOj/Y+AJ3Ta6+9lv322y/LLrts/v73v7f3cYAWmDp1arbaaqtssMEGOffcc9O/f/889dRTuf/++9v7aEADXn/99Sy22GI5/vjjs/zyy+edd97J1VdfnUMOOSQPPPBALrjggvY+ItACvg5vWwoyDTn66KOz5JJLZquttsqpp57a3scBGvTGG29kt912yyabbJLf/OY3aWpq+iDbfffd2/FkQKNGjBiRiy66aK63jRkzJs8991wuuuiinHPOOendu3c7nQ5oKV+Hty1/xXo+e+utt3L44Ydn9dVXz+KLL56+fftmnXXWyZVXXlk5c95552XFFVdM796988lPfjKXXXbZh95nxowZ2X///bPccsulV69eGTp0aE466aQ2+atUt912W3784x/nggsuSPfu3Vv98aGz6cz3+vLLL88//vGPHHnkkXOVY1jQdeZ7XWXAgAHp1q2b37tZYHWFe+3r8LbnFeT57O23386LL76YI444IoMGDco777yTG2+8Mdtvv30mTJiQPfbYY673nzJlSqZOnZqTTz45iyyySMaPH59ddtklPXr0yA477JDkX5dy1KhR6datW0444YQMGzYsd955Z0499dRMnz49EyZMKJ5pyJAhSZLp06fXPf+bb76ZffbZJ//1X/+VNdZYI1OmTGno4wBdSWe+17feemuSZM6cOVl//fVz9913Z5FFFskWW2yRH/zgB1l22WUb+6BAJ9eZ7/X7arVa5syZk1dffTXXX399Jk6cmMMPPzw9evjyjwVTZ7/Xvg6fT2q0mgkTJtSS1O65555mz8yePbv27rvv1vbZZ5/ayJEj58qS1BZaaKHajBkz5nr/ESNG1IYPH/7B2/bff/9anz59ak8++eRc89///vdrSWoPPfTQXI85bty4ud5v2LBhtWHDhjXrvIcffnhthRVWqL3xxhu1Wq1WGzduXC1JbdasWc2ah86mq9/r0aNH15LUllhiidpRRx1Vu/nmm2vnnnturV+/frXhw4fXXn/99Wb/uKGz6Or3+n2nn356LUktSa2pqal27LHHNnsWOpsF4V77Onz+8Fes28Hll1+e9dZbL3369EmPHj3Ss2fPXHjhhXn44Yc/9L6bbrppll566Q/+v3v37tl5550zbdq0PPPMM0mS3/72t9l4442z7LLLZvbs2R/8N2bMmCTJLbfcUjzPtGnTMm3atLrnvvvuu/Pf//3fOe+887LQQgvNyw8ZurzOeq/fe++9JMnOO++c73znO9l4442z//7758ILL8y0adPys5/9rNkfA+hqOuu9ft9ee+2Ve+65J9ddd12OOuqofO9738shhxzS7HnoijrrvfZ1+PyjIM9nkydPzk477ZRBgwblkksuyZ133pl77rkne++9d956660Pvf8yyyxT+bYXXnghSTJz5sz85je/Sc+ePef6b5VVVkmSVvvW73vvvXe23377rLXWWnn55Zfz8ssvf3DmV155Ja+++mqrPA90Np35Xvfr1y9JMnr06LnePnr06DQ1NeW+++5rleeBzqYz3+t/f/611lorm2++ec4444ycfPLJOfvss32HehZYnfle+zp8/vGPUOazSy65JEOHDs2kSZPm+oY4b7/99ke+/4wZMyrf9v4Xtv3798+qq66a00477SMfo7X+DeFDDz2Uhx56KJdffvmHsmHDhmW11VbLAw880CrPBZ1JZ77Xq6666kd+w5H3devmz1FZMHXme11l1KhRSZLHHnssI0eObNPngo6oM99rX4fPPwryfNbU1JRevXrNdSlnzJhR+d3zbrrppsycOfODv94xZ86cTJo0KcOGDctyyy2XJBk7dmyuvvrqDBs2LEsuuWSbnX3q1KkfetvEiRNz0UUX5de//nUGDRrUZs8NHVlnvtfbbbddjj322FxzzTXZbrvtPnj7Nddck1qtlrXXXrvNnhs6ss58r6u8//v48OHD5/tzQ0fQme+1r8PnHwW5Ddx8880f+Z3ottxyy4wdOzaTJ0/OgQcemB122CFPP/10TjnllAwcODCPP/74h2b69++fTTbZJMcff/wH3z3vkUcemesVn5NPPjk33HBD1l133Rx66KFZaaWV8tZbb2X69Om5+uqrc+65535wiT/K+79R1vv3DxtttNGH3va///u/SZL11lsv/fv3L85DZ9ZV7/WIESNy0EEHZfz48Vl00UUzZsyYPPbYYznuuOMycuTI7LTTTs38CEHn01Xv9bhx4zJz5sx87nOfy6BBg/Lyyy/n2muvzfnnn58dd9wxa665ZjM/QtD5dNV77evw+ai9v0tYV/L+d8+r+u+JJ56o1Wq12hlnnFEbMmRIrXfv3rWVV165dv7553/wXej+XZLaQQcdVBs/fnxt2LBhtZ49e9ZGjBhRu/TSSz/03LNmzaodeuihtaFDh9Z69uxZ69u3b23NNdesHXvssbXXXnttrsf8z++eN3jw4NrgwYMb+jH77nl0dQvCvZ49e3btjDPOqA0fPrzWs2fP2sCBA2sHHHBA7aWXXpqXDxV0Gl39Xk+ZMqW22Wab1ZZeeulajx49an369KmNGjWqdtZZZ9Xefffdef54QWfQ1e/1R/F1eNtoqtVqtbYq3wAAANBZ+O4rAAAAEAUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJkh7Nfcempqa2PAcsMDrS6nH3GlqHew1dj3sNXU9z7rVXkAEAACAKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAkqRHex8AYH5Zeumli/n//u//VmYjRowozj7xxBOV2T777FOcvfvuuyuz119/vTgLAEDr8QoyAAAAREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEhizRMd3PDhw4v517/+9crsyiuvLM7eeOONDZ2Jzuvwww8v5kOGDKnMnnrqqeLsoosuWplNmTKlODt+/PjK7Jvf/GZxFgCA1uMVZAAAAIiCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJPYg08EdeOCBxfzggw+uzFZfffXirD3IXdPaa69dme29997F2Xvvvbcy22CDDYqzSy+9dGXWr1+/4mz//v2LOdD51Gq1hrK29vjjj1dmf/rTn4qzF1xwQWV23XXXNXwmgI7EK8gAAAAQBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIEnSVGvmroGmpqa2PkuXUVr3kiRf/vKXK7O33367OHv22Wc3dKbOaurUqcV8o402qszee++94mz37t0bOVKLted6j//UFe/1NddcU5mNHj26OLv99ttXZr/+9a8bPRILAPea/3TxxRdXZrvuuut8PMncSr8+6v06fu211yqzwYMHF2dffvnlYt4Rudcd1/3331+ZrbbaasXZ0v277LLLGj5TW1pxxRWL+TvvvFOZTZ8+vZVP07k15157BRkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIEnSo70P0FkNGDCgMjv44IOLs8cdd1xl9re//a042xX3IPft27cy22CDDRp+3FNPPbXhWTquUaNGFfNNNtmkMpsyZUpx9sorr2zoTHxY7969K7OPfexjxdk333yzMivteoSO5Otf/3plNmfOnOLsYostVszHjBlTmfXq1at8sBZ45ZVXKrN6PyaYF5/85CeL+bLLLluZ1dtz++qrrzZ0prY2YsSIyuyaa64pzu6+++6VmT3I884ryAAAABAFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiTVPlT73uc8V8/32268y+/KXv9zw83bFNTOllVhJeR1T9+7dG37eP//5zw3P0nEttNBCxbxnz56V2eTJk4uz9VZDLGg22mijyuyoo44qzpbu/TLLLFOcLa2kqPf59cknnyzmML+8+OKLldnJJ59cnN1///2L+Re+8IWGzlTP66+/Xsy32GKLyqyjrs6h4yr9fn7YYYcVZ/v371+Z3X777cXZm2++uXywdnLSSSdVZssvv3xxdquttqrM6n08+DCvIAMAAEAUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJLEHudLs2bOL+bbbbtvwY8+ZM6cyu+qqqxp+3PbUrVv1n7WstdZaxdmvfvWrDT9v6WP5wAMPNPy4dE3PPvtsex9hvivtHD722GOLs6VdrH/5y1+Ks+edd175YAV77rlnZTZ16tTi7Oabb16ZTZs2reEzsWBaYoklKrPtttuuOLv33ntXZquvvnpxduGFFy7mLTFz5szKbPfddy/OPvTQQ619HBZga665ZmX2la98peHHrbf3980332z4sTuqpZZaqr2P0KV4BRkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJLHmqdKXv/zlYt6nT5/KrN63j99nn30qs5tuuql8sA6qtBpi4sSJbfa8xxxzTGVmpcuC6ZVXXqnMnnzyyfl4kvljkUUWKeannXZaZVZvjcZll11WmZU+jyUtW6NRet6LLrqoOFtaEXX88cc3fCY6r7322qsyW3/99Yuzu+66a2X2sY99rDjb1NRUmdVqteJsPa+//npl9otf/KI4+53vfKcye+yxxxo+E8yrj3/84w3P3nbbbZVZ6fe9rmrChAntfYQuxSvIAAAAEAUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJuvge5G7dyv1///33r8x222234uycOXMqs7POOqs4+/Of/7yYd0QrrLBCMd9+++3b5HkfeOCBYt5Z90bTdv75z39WZl1xN3a9fY+lXceXX355cba0P/add94pzrbESy+9VJn98Y9/LM7usssulZk9yAumo446qjJbaaWVGn7cluwyrjc7efLkYl76tfzII480dCaY33bfffeGZ2fMmFGZvfHGGw0/bltaZJFFivnAgQPn00moxyvIAAAAEAUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACBJF1/ztO666xbz8ePHN/zYP/zhDyuzo48+uuHH7ajGjh1bzLfccsuGH/vBBx+szA466KDi7H333dfw80JnsNpqqxXzffbZp5g/++yzldm3vvWt4mxbrnJq1J///OdiXlrzxILpqaeeqsxasuapLS233HLFfOWVV67MrHliQfDxj3+8MuvTp09x9rXXXmvt4zRLvTVO66233nw6CfV4BRkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIEkX2IO8+uqrV2alXcX13HvvvcV84sSJDT92R3XIIYdUZieeeGJxtkePxn8pXXLJJZXZXXfd1fDjQlfwjW98o5gvssgixfzwww+vzP761782dKb29IUvfKGY/+Uvf5lPJ6GzOOGEEyqzm266qTi72GKLVWbbb799cXbhhReuzJZffvni7KhRo4r5T3/608rs6KOPLs6ec845xRzml3PPPbcyGz16dHF27bXXrsxKX1cmyZVXXlk+WBvZdtttG56dOXNmMZ8xY0bDj82HeQUZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACTpAmuePv7xj1dma6yxRsOPe9VVVxXzBx54oOHHbi9f+cpXinlpldOSSy7Z8PM+88wzxby0ruK9995r+HmhK+jbt28xf+KJJ4r5L37xi9Y8Tod3zz33tPcR6GDuvvvuhrJ6jj/++GJeWhG1yy67FGfrrWoqrYk69thji7M33HBDZfbYY48VZ6E1XXvttZXZ+PHji7MHHnhgZVZvHWC9vKSpqakyq9VqDT9uPY8//ngxnzZtWps994LIK8gAAAAQBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEmSplozl3aV9n61pdKe4yS5/vrrK7MRI0YUZ5988snKbPPNNy/OPvvss5VZt27lP3dYaKGFKrNRo0YVZz/72c9WZttss01xduDAgcW8f//+xbyktK+43k7p7bbbrjKbM2dOw2fqqNpyT968aq973RIbbrhhMb/xxhsrs0033bQ4e+uttzZ0ppYq7Tr++9//Xpy96KKLivn+++/f0Jna07rrrluZTZkypTi78847V2Y33XRTw2eqx71mfrriiisqs3pfC9xxxx2V2QYbbNDwmboi97r99OjRo5j37t27MjvggAOKs4svvnhDZ2qpsWPHFvNVV121Mrv99tuLs/W+NuL/NOdeewUZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACBJUl4y1gH893//dzGvt+u45Pnnn6/MTjnllOLsyiuvXJmV9hwnyfDhw8sHK7jtttsqs/322684W9q1miRXX311Q2dKktNOO60yO+GEExp+XJhX3bt3r8y23Xbb4mx77UHu2bNnZdarV6/i7EMPPdTax2lz9XbFH3PMMZXZz372s+JsW+46ho7iyCOPrMzWXHPN4uwaa6xRmdX7muqRRx4pHwxayezZsxvOv//977f2cZpl0UUXLeZbb711Ma/3eyPzj58JAAAAiIIMAAAASRRkAAAASKIgAwAAQBIF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AQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIEnSVKvVau19CAAAAGhvXkEGAACAKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEkUZAAAAEiiILeqiRMnpqmpKffee2+rPF5TU1MOPvjgVnmsf3/ME088seH54447LmPHjs2gQYPS1NSUvfbaq9XOBh1RV7/XTz/9dLbbbrussMIKWWSRRbL44otn5MiROfvsszN79uxWPSd0FF39XifJu+++m5NOOilDhgxJ7969M2LEiPzoRz9qvQNCB7Mg3OvHHnssX/ziF7Pkkktm4YUXzmc/+9lMmTKl9Q5IEgWZeXTmmWfmhRdeyNZbb51evXq193GAFnr99dez2GKL5fjjj8+UKVNy2WWXZf31188hhxySr33ta+19PKBBBx54YE4//fQcdNBBue6667Lddtvl61//er797W+399GABkyfPj3rrLNOHn300Zx77rm5/PLLM2DAgGy77bb51a9+1d7H61J6tPcB6FxeffXVdOv2rz9Xufjii9v5NEBLjRgxIhdddNFcbxszZkyee+65XHTRRTnnnHPSu3fvdjod0IiHHnooF154YU477bQceeSRSZKNNtooL7zwQk499dR87WtfS9++fdv5lMC8OOOMM/LGG2/kuuuuy6BBg5IkW2yxRT796U/nG9/4RrbbbrsPvkanZXwU57O33norhx9+eFZfffUsvvji6du3b9ZZZ51ceeWVlTPnnXdeVlxxxfTu3Tuf/OQnc9lll33ofWbMmJH9998/yy23XHr16pWhQ4fmpJNOavW/IuniwYd19nv9UQYMGJBu3bqle/fubf5c0BF15nv961//OrVaLV/5ylfmevtXvvKVvPnmm7n22mtb7bmgM+nM9/qOO+7Iaqut9kE5TpLu3btnzJgxefrpp3P33Xe32nMt6LyCPJ+9/fbbefHFF3PEEUdk0KBBeeedd3LjjTdm++23z4QJE7LHHnvM9f5TpkzJ1KlTc/LJJ2eRRRbJ+PHjs8suu6RHjx7ZYYcdkvzrUo4aNSrdunXLCSeckGHDhuXOO+/MqaeemunTp2fChAnFMw0ZMiTJv/7qBjDvusK9rtVqmTNnTl599dVcf/31mThxYg4//PD06OG3CRZMnfleP/jggxkwYECWWWaZud6+6qqrfpDDgqgz3+t33nnnI//mx/t/y+tPf/pT1l577WZ+JCiq0WomTJhQS1K75557mj0ze/bs2rvvvlvbZ599aiNHjpwrS1JbaKGFajNmzJjr/UeMGFEbPnz4B2/bf//9a3369Kk9+eSTc81///vfryWpPfTQQ3M95rhx4+Z6v2HDhtWGDRvW7DO/b5FFFqntueee8zwHncmCcq9PP/30WpJaklpTU1Pt2GOPbfYsdDZd/V5//vOfr6200kofmfXq1av21a9+te5jQGfT1e/1tttuW1tiiSVqr7766lxv32CDDWpJat/+9rfrPgbN4+/LtoPLL7886623Xvr06ZMePXqkZ8+eufDCC/Pwww9/6H033XTTLL300h/8f/fu3bPzzjtn2rRpeeaZZ5Ikv/3tb7Pxxhtn2WWXzezZsz/4b8yYMUmSW265pXieadOmZdq0aa34I4QFT2e/13vttVfuueeeXHfddTnqqKPyve99L4ccckiz56Er6sz3uqmpqaEMurrOeq8PPvjg/POf/8wee+yRv/3tb5k5c2aOP/74/O53v0vin0G2Jh/J+Wzy5MnZaaedMmjQoFxyySW58847c88992TvvffOW2+99aH3/8+/HvXvb3vhhReSJDNnzsxvfvOb9OzZc67/VllllSTJ888/34Y/IqAr3Otlllkma621VjbffPOcccYZOfnkk3P22Wfn/vvvb9Xngc6iM9/rfv36ffCc/+7111+v/GuasCDozPd60003zYQJE3Lrrbdm2LBhWWaZZTJ58uSccsopSTLXv02mZfzjsvnskksuydChQzNp0qS5/gT37bff/sj3nzFjRuXb+vXrlyTp379/Vl111Zx22mkf+RjLLrtsS48NFHTFez1q1Kgk/9q5OHLkyDZ9LuiIOvO9/vSnP53LLrssM2bMmOsL/D//+c9Jkk996lOt8jzQ2XTme50ke+65Z3bbbbc8/vjj6dmzZ4YPH57TTz89TU1N2WCDDVrteRZ0CvJ81tTUlF69es11KWfMmFH53fNuuummzJw584O/3jFnzpxMmjQpw4YNy3LLLZckGTt2bK6++uoMGzYsSy65ZNv/IIC5dMV7PXXq1CTJ8OHD5/tzQ0fQme/1Nttsk+OOOy4XXXRRvvnNb37w9okTJ2ahhRbKFlts0WbPDR1ZZ77X7+vRo0dWXnnlJMk///nP/PjHP84222yTwYMHt/lzLygU5DZw8803f+R3ottyyy0zduzYTJ48OQceeGB22GGHPP300znllFMycODAPP744x+a6d+/fzbZZJMcf/zxH3z3vEceeWSubzF/8skn54Ybbsi6666bQw89NCuttFLeeuutTJ8+PVdffXXOPffcDy7xR3n/C+Dm/PuHW265JbNmzUryr08STz75ZH75y18mSTbccMMMGDCg7mNAZ9RV7/W4ceMyc+bMfO5zn8ugQYPy8ssv59prr83555+fHXfcMWuuuWYzP0LQ+XTVe73KKqtkn332ybhx49K9e/d85jOfyfXXX58f//jHOfXUU/0Va7q0rnqvn3vuufzgBz/Ieuutl0UXXTSPPPJIvvvd76Zbt24555xzmvnRoVna+7uEdSXvf/e8qv+eeOKJWq1Wq51xxhm1IUOG1Hr37l1beeWVa+eff35t3Lhxtf/86UhSO+igg2rjx4+vDRs2rNazZ8/aiBEjapdeeumHnnvWrFm1Qw89tDZ06NBaz549a3379q2tueaatWOPPbb22muvzfWY//nd8wYPHlwbPHhws36MG264YeWPb+rUqfPy4YJOoavf6ylTptQ222yz2tJLL13r0aNHrU+fPrVRo0bVzjrrrNq77747zx8v6Ay6+r2u1Wq1d955pzZu3Lja8ssvX+vVq1dtxRVXrJ111lnz9HGCzqSr3+sXXnihtvnmm9cGDBhQ69mzZ2355ZevHXLIIbVZs2bN88eKsqZarVZri+INAAAAnYnvYg0AAABRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkiQ9mvuOTU1NbXkOWGB0pM1q7jW0Dvcauh73Grqe5txrryADAABAFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkCTp0d4HgA033LAy+9///d/i7I9+9KPK7NBDD230SADQKfXv37+YH3DAAZXZq6++Wpz97//+70aOBNCpeAUZAAAAoiADAABAEgUZAAAAkijIAAAAkERBBgAAgCQKMgAAACRRkAEAACBJ0lSr1WrNesemprY+C13UUkstVcwnTZpUmX3uc58rzj733HOV2QYbbFCcnTZtWjFvK828cvOFew2tw72mNQ0cOLCY77777pXZl770peLsaqutVpm98sorxdmNN964MnvggQeKs52Re91x9e7duzKr93XnPvvsU5ktuuiixdmtttqqMvvEJz5RnL3ggguK+RFHHFGZ1dtRTvM15157BRkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJEl6tPcB6Pr22GOPYl5vlVPJww8/XJm99NJLDT8u/KdvfOMbxXzVVVetzOrdgZbo1q3855z3339/ZXbxxRcXZ6+66qrK7LHHHisfDGjYoEGDivnpp5/eJs+72GKLFfPf/OY3ldnHP/7x1j4OC7A999yzmH/5y1+uzErryOqpt06rtCKo3vqg0nqpJHnkkUcqszPPPLM4S+vyCjIAAABEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQJKkqVZvadf771hnLxhd27LLLlvMJ02aVJl99rOfLc527969MrvjjjuKs+eff35lVm/Ha3tp5pWbLzrjvT722GOL+Ve/+tU2ed7llluumLfXz2tLdjbW89BDD1Vmq622WsOP2xW518yLK664ophvtNFGxbzevuK28vrrr1dm66+/fnH2T3/6U2sfp8251+3n2WefLeZLL710w4/92GOPVWb1fp2uvfbaDT1ukqyzzjrFvPR164EHHlicpfmac6+9ggwAAABRkAEAACCJggwAAABJFGQAAABIoiADAABAEgUZAAAAkiQ92vsAdA6bbbZZMV933XXb5Hl//OMfF/NLLrmkTZ6XjqveGqdBgwbNp5M034MPPljMBw4cWJn169evtY/TbC+99FK7PTd0dPVWv40ePboyW2mllYqz7bXGqZ5FFlmkMrv++uuLs0cffXRlNnHixEaPRCe23377VWbLLLNMcba0qufnP/95cfaYY46pzJ555pnibOn35FdffbU4+/jjjxfzrbbaqpgz/3gFGQAAAKIgAwAAQBIFGQAAAJIo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yuyrX/1qcbatdh2vueaaxdyeY2BeLLroopXZlClTirPdulX/+et7771XnJ00aVJlZs9x5/X5z3++MuvevXtxtrTffPTo0cXZWbNmlQ+2gBkxYkRlttZaaxVnDznkkIafd86cOZXZLbfc0vDj0nmdeuqplVm9Pch9+vSpzHbffffi7HbbbVeZvfLKK8XZ0j7iAQMGFGd79epVzF977bXK7OSTTy7OfulLX6rMRo4c2fC5+vXrV5ztqryCDAAAAFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSWPPUsE984hOV2Re/+MWGH/epp54q5kceeWRl9sgjjxRn33rrrYbOBCyYNtxww8psgw02KM6WVjnV+zw3YcKE8sHokHbYYYdiXlrl9NJLLxVnS2tZuuIap4UWWqiYlz6W++23X3F23333rcw+9rGPFWcHDx5cmdVb33bOOedUZs8//3xxlq6ptN5rm222Kc6Wfj0ttdRSxdnSCsPFFlusOFv6tVrvc9EFF1xQzE855ZRiXtK/f//KbI011ijONjU1VWaf+9znirO//OUvywfrpLyCDAAAAFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSKMgAAACQxB7kSqusskoxb6u9X/X2F954441t8rzAgmfs2LHF/Cc/+UmbPO9dd91VzKdNm9Ymz0vbWmeddYp5t27VfyZ/1llnFWfvuOOOhs7UnpZddtnK7Gtf+1px9p///Gcx32qrrSqzoUOHFmeXX375Yl7ywgsvVGaXXHJJcfawww5r+HlZ8Pz2t79tON94442Ls/369WvoTEn5969nnnmm4cdtqfvuu68yq9VqDT/uyJEjG57tzLyCDAAAAFGQAQAAIImCDAAAAEkUZAAAAEiiIAMAAEASBRkAAACSdPE1T3369Cnma6yxRmVWb13BoEGDGjoTQGtadNFFi/mGG25YmdVb49S3b9+GzpQkr776amU2ceLEhh+XjqveGp/33nuvMps1a1ZxtvTrfLHFFivOzpw5szKbPXt2cXahhRaqzI455pjibGlt41JLLVWcbS8vv/xyMT/88MMrs4svvriVTwONmTp1ansfgU7OK8gAAAAQBRkAAACSKMgAAACQREEGAACAJAoyAAAAJFGQAQAAIImCDAAAAEm6+B7kYcOGFXN70oDObsqUKcV8gw02mE8nmds222xTmd1yyy3z8STML6+99loxX3jhhSuzs88+uzi75557Vmaf+cxnirM/+9nPKrPSvu4kGTJkSGU2evTo4mxHVdpHffDBBxdnf/7zn7f2cQA6HK8gAwAAQBRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkXXzNE8D8suKKK1ZmW221VXF28cUXr8yOP/744my3buU/5yytdKnnqquuqsx+8IMfFGetclrwbLrppsX89ttvr8y6d+9enK23yqlk1113bXi2vcyZM6eYP/HEE5XZOeecU5x95ZVXKjNrnKBzampqaiirl9f7GqOrWjB/1AAAAPAfFGQAAACIggwAAABJFGQAAABIoiADAABAEgUZAAAAkijIAAAAkMQe5Dbx1FNPFfOdd965Mnv44Ydb+ziwQOnXr19lNmHChOLsaqutVpnV2yP4sY99rDLr27dvcbakVqsV83p7jkufjyZNmlScPemkkyqzN998szjLgufuu+8u5t/85jcrs5NPPrk4u/DCCzd0ppZ69913K7N6d7PkJz/5STG/6667ivnFF1/c8HMDXU/p81FLPlfV+xqjq/IKMgAAAERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJFGQAAABIYs1Tw2bMmFGZfeELXyjOPvjgg619HFhglNY4JeVVTltuuWXDz1tvzVNL1ii0xO9+97ti/o1vfKMyu/fee1v7OFDpzDPPrMzuuOOO4uznP//51j5Os5x//vmV2XPPPTcfTwJQ7emnn67M6q1lbK81eh2ZV5ABAAAgCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIkTbVmLu+stwMUaJ722pf7UTrjvd5xxx2L+c9//vM2ed56H6vXX3+9MnvhhReKsz/96U8rsz//+c/F2V/+8pfFnPnDvYaux72mK7jiiiuK+SabbFKZHXfcccXZH/3oRw2dqT015157BRkAAACiIAMAAEASBRkAAACSKMgAAACQREEGAACAJAoyAAAAJLHmCeY7ayNaZsUVVyzm11xzTWU2ePDghp/3iCOOKOaPPvpoQ2eia3Cvoetxr6HrseYJAAAAmklBBgAAgCjIAAAAkERBBgAAgCQKMgAAACRRkAEAACCJggwAAABJ7EGG+c5eReh63Gvoetxr6HrsQQYAAIBmUpABAAAgCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASJI01Wq1WnsfAgAAANqbV5ABAAAgCjIAAAAkUZABAAAgiYIMAAAASRRkAAAASKIgAwAAQBIFGQAAAJIoyAAAAJBEQQYAAIAkyf8H6MkmgA2IZPkAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 1000x1000 with 16 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "# Get 16 random indices\n",
    "indices = np.random.choice(len(train_dataset), size=16, replace=False)\n",
    "\n",
    "# Get the corresponding images and labels\n",
    "images = [train_dataset[i][0] for i in indices]\n",
    "labels = [train_dataset[i][1] for i in indices]\n",
    "\n",
    "# Create a figure with 4x4 subplots\n",
    "fig, axes = plt.subplots(4, 4, figsize=(10, 10))\n",
    "\n",
    "# Iterate over the subplots and display the images with labels\n",
    "for i, ax in enumerate(axes.flat):\n",
    "    ax.imshow(images[i].squeeze(), cmap='gray')\n",
    "    ax.set_title(f\"Label: {labels[i]}\")\n",
    "    ax.axis('off')\n",
    "\n",
    "# Adjust the spacing between subplots\n",
    "plt.tight_layout()\n",
    "\n",
    "# Show the figure\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Build the RNN Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(-0.1020, grad_fn=<SelectBackward0>)\n",
      "tensor(-0.0569, grad_fn=<SelectBackward0>)\n",
      "ParameterModel(\n",
      "  (relu): ReLU()\n",
      ")\n",
      "torch.Size([64, 10])\n",
      "Number of parameters: 101,770\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import math\n",
    "\n",
    "class ParameterModel(nn.Module):\n",
    "    def __init__(self, input_size=28*28, hidden_size=128, num_classes=10):\n",
    "        super(ParameterModel, self).__init__()\n",
    "        self.fc1 = nn.parameter.Parameter(torch.randn(input_size, hidden_size))   \n",
    "        nn.init.kaiming_uniform_(self.fc1, a=math.sqrt(5))\n",
    "        self.bias1 = nn.parameter.Parameter(torch.randn(hidden_size))\n",
    "        self.reset_bias(self.fc1, self.bias1)\n",
    "        self.relu = nn.ReLU()\n",
    "        self.fc2 = nn.parameter.Parameter(torch.randn(hidden_size, num_classes))\n",
    "        nn.init.kaiming_uniform_(self.fc2, a=math.sqrt(5))\n",
    "        self.bias2 = nn.parameter.Parameter(torch.randn(num_classes))\n",
    "        self.reset_bias(self.fc2, self.bias2)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = x.view(x.size(0), -1)\n",
    "        x = torch.einsum('bi,ij->bj', (x, self.fc1)) + self.bias1\n",
    "        x = self.relu(x)\n",
    "        x = torch.einsum('bi,ij->bj', (x, self.fc2)) + self.bias2\n",
    "        return x\n",
    "    \n",
    "    def reset_bias(self, weight, bias):\n",
    "        # Setting a=sqrt(5) in kaiming_uniform is the same as initializing with\n",
    "        # uniform(-1/sqrt(in_features), 1/sqrt(in_features)). For details, see\n",
    "        # https://github.com/pytorch/pytorch/issues/57109\n",
    "        \n",
    "        fan_in, _ = nn.init._calculate_fan_in_and_fan_out(weight)\n",
    "        bound = 1 / math.sqrt(fan_in) if fan_in > 0 else 0\n",
    "        nn.init.uniform_(bias, -bound, bound)\n",
    "        return bias\n",
    "\n",
    "x = torch.randn(64, 1, 28, 28)\n",
    "model = ParameterModel()\n",
    "print(model)\n",
    "print(model(x).shape)\n",
    "\n",
    "# print the number of parameters\n",
    "num_params = sum(p.numel() for p in model.parameters())\n",
    "# Use comma to print the number in a more readable format\n",
    "print(f\"Number of parameters: {num_params:,}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define the loss function and optimizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "model.to(device)\n",
    "\n",
    "# Define the loss function and optimizer\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Train the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 10%|█         | 1/10 [00:08<01:18,  8.73s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 1, Loss: 0.3476\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 20%|██        | 2/10 [00:17<01:09,  8.64s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 2, Loss: 0.1807\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 30%|███       | 3/10 [00:25<01:00,  8.60s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 3, Loss: 0.1366\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 40%|████      | 4/10 [00:34<00:51,  8.57s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 4, Loss: 0.1156\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 50%|█████     | 5/10 [00:43<00:43,  8.65s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 5, Loss: 0.1010\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 60%|██████    | 6/10 [00:51<00:34,  8.61s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 6, Loss: 0.0884\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 70%|███████   | 7/10 [01:00<00:25,  8.59s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 7, Loss: 0.0801\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 80%|████████  | 8/10 [01:08<00:17,  8.58s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 8, Loss: 0.0740\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " 90%|█████████ | 9/10 [01:17<00:08,  8.63s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 9, Loss: 0.0676\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 10/10 [01:26<00:00,  8.61s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 10, Loss: 0.0634\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "from tqdm import tqdm\n",
    "\n",
    "num_epochs = 10\n",
    "\n",
    "model.train()\n",
    "for epoch in tqdm(range(num_epochs)):\n",
    "    total_loss = 0\n",
    "    \n",
    "    for images, labels in train_loader:\n",
    "        images = images.to(device)\n",
    "        labels = labels.to(device)\n",
    "        \n",
    "        # Forward pass\n",
    "        outputs = model(images)\n",
    "        loss = criterion(outputs, labels)\n",
    "        \n",
    "        # Backward and optimize\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "        total_loss += loss.item()\n",
    "    \n",
    "    avg_loss = total_loss / len(train_loader)\n",
    "    print(f\"Epoch: {epoch+1}, Loss: {avg_loss:.4f}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluate the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test Accuracy: 0.9728\n"
     ]
    }
   ],
   "source": [
    "model.eval()  # Set the model to evaluation mode\n",
    "\n",
    "correct = 0\n",
    "total = 0\n",
    "\n",
    "with torch.no_grad():\n",
    "    for images, labels in test_loader:\n",
    "        images = images.to(device)\n",
    "        labels = labels.to(device)\n",
    "        \n",
    "        # Forward pass\n",
    "        outputs = model(images)\n",
    "        _, predicted = torch.max(outputs.data, 1)\n",
    "        \n",
    "        total += labels.size(0)\n",
    "        correct += (predicted == labels).sum().item()\n",
    "\n",
    "accuracy = correct / total\n",
    "print(f\"Test Accuracy: {accuracy:.4f}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Predict on sample images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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Vavo27dvPPnkkzFt2rQYN25cg+2+9KUvNfj8ySefjNWrV8f555/f4HvfsmVLDBs2LBYtWhTr1q2LdevWxaJFi+LMM8+M1q1b53y7du3i9NNP3+H6Hn300Tj88MPji1/8YunvbcOGDTFv3rw444wzok2bNg3Wedppp8WGDRviL3/5S0REzJ8/P4488sjo379/g32cc8452+z3pJNOivr6+pg8efIO1zBx4sSoqqpq0rbs3bx9tI+ZOXNmnH322XHWWWfFZZddFl27do2WLVvGzTffHLfddts223ft2nW7j61atSp69OgRK1asiNmzZ0dVVVWjx/wol4u+34UXXhhnnnlmHHvssfHWW29FxP9e8CIi3nnnnaiuro527do1a99nn312XHbZZVGpVKJdu3ZRV1fX6FschxxySIPPt771s/WttMasXr06KpVKbNmy5UOfzw+zcuXK6Nmz5w63a8yqVauivr4+pk+fHtOnT290m60/o1WrVkXv3r2btcbtefrpp2PGjBkxc+bM2LBhQ/7MtmzZEvX19fHWW2/F/vvvH9XV1c0+BruPKOxj7r777ujdu3fcd999Da6N37hxY6PbL1++fLuPdejQISIiOnbsGP369Ysf/vCHje5jZ102+vzzz8fzzz8fDzzwwDZfq6uri/79+8ezzz7brH136tQpjj322B1u98G/J+jYsWNEREyfPj2OP/74Rme6dOkSmzZtikql8qHP547Wt/XMrKz27dtHixYt4mtf+1pcfPHFjW6zNQQdOnRo9hq3Z/HixVEURZxxxhnbfO2VV16J9u3bxw033BCXXnpps4/B7iMK+5hKpRKtWrVq8OK2fPny7V59NG/evFixYkW+hbR58+a47777oq6uLnr06BERESNHjoxHHnkk6urqdullhvPnz9/msTvuuCPuvPPOmDVrVnTv3n2XHXt7Bg0aFAcffHAsXrz4Q//Qr1WrVjFgwICYOXNm/OQnP8m3kNasWROzZ8/e4XGGDx8ekydPjieeeCJOOeWURrfZ+j/t9evXN3i8TZs2MXjw4Pj73/8e/fr1i1atWm33OIMHD47rrrsunnvuuQZvIf3mN7/Z4Rq3Z9iwYY3+7L7yla9E796940c/+lEcdthhzd4/u5cofAw98cQTjV7Jc9ppp8XIkSNj5syZMW7cuBg9enS88sorcfXVV8chhxwSL774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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import random\n",
    "\n",
    "# Set the model to evaluation mode\n",
    "model.eval()\n",
    "\n",
    "# Select a random image from the test dataset\n",
    "random_index = random.randint(0, len(test_dataset) - 1)\n",
    "image, label = test_dataset[random_index]\n",
    "\n",
    "# Move the image to the device\n",
    "image = image.to(device)\n",
    "\n",
    "# Forward pass to get the predicted label\n",
    "output = model(image.unsqueeze(0))\n",
    "_, predicted_label = torch.max(output, 1)\n",
    "\n",
    "# Convert the image tensor to a numpy array\n",
    "image_np = image.cpu().numpy()\n",
    "\n",
    "# Display the image, its label, and the predicted label\n",
    "plt.imshow(image_np.squeeze(), cmap='gray')\n",
    "plt.title(f\"Label: {label}, Predicted: {predicted_label.item()}\")\n",
    "plt.axis('off')\n",
    "plt.show()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "fuyu",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
